home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
hamradio
/
tnos-2.000
/
tnos-2
/
trace.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-21
|
15KB
|
603 lines
/* Packet tracing - top level and generic routines, including hex/ascii
* Copyright 1991 Phil Karn, KA9Q
*
* Mods by G1EMM
*
* Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
*/
#include "global.h"
#include "ctype.h"
#include "commands.h"
#include <time.h>
#ifdef ANSIPROTO
#include <stdarg.h>
#endif
#include "mbuf.h"
#include "iface.h"
#include "pktdrvr.h"
#include "session.h"
#include "trace.h"
#include "usock.h"
#if !defined(_lint) && !defined(MSDOS)
static char rcsid[] OPTIONAL = "$Id: trace.c,v 1.16 1996/07/21 23:54:49 root Exp root $";
#endif
/* this variable and the patch to traceprintf assumes that no pwaits
will be placed in any of the files used for tracing. */
int tracesock;
#ifdef TRACE
static void ascii_dump __ARGS ((FILE * fp, struct mbuf ** bpp));
static void ctohex __ARGS ((char *buf, int16 c));
static void fmtline __ARGS ((FILE * fp, int16 addr, char *buf, int16 len));
static void hex_dump __ARGS ((FILE * fp, struct mbuf ** bpp, int iftype));
static void showtrace __ARGS ((struct iface * ifp));
static void plain_dump __ARGS ((FILE * fp, register struct mbuf ** bpp));
#ifdef MULTITASK
extern int Nokeys;
#endif
extern int Tracesession;
extern struct session *Trace;
#include "slip.h"
#ifdef MONITOR
int Trace_compact_header = 0;
static const char *kissname __ARGS ((struct iface * ifp, struct mbuf * bp, unsigned type));
static const char *
kissname (struct iface *ifp, struct mbuf *bp, unsigned type)
{
int port;
if (ifp->type != CL_AX25 || type != CL_KISS)
return ifp->name;
port = (bp->data[0] & 0xF0) >> 4;
if (Slip[ifp->xdev].kiss[port] == NULLIF)
return ifp->name;
return Slip[ifp->xdev].kiss[port]->name;
}
#endif
int
dostrace (int argc, char *argv[], void *p OPTIONAL)
{
if (Trace == NULLSESSION) {
if (argc > 1)
tputs ("Session tracing not available!\007\n");
argc = 0; /* No session setup, so don't allow turning it on ! */
}
return setbool (&Tracesession, "Trace to session", argc, argv);
}
/* Redefined here so that programs calling dump in the library won't pull
* in the rest of the package
*/
static char nospace[] = "No space!!\n";
struct tracecmd DFAR Tracecmd[] =
{
{ "input", IF_TRACE_IN, IF_TRACE_IN },
{ "-input", 0, IF_TRACE_IN },
{ "output", IF_TRACE_OUT, IF_TRACE_OUT },
{ "-output", 0, IF_TRACE_OUT },
{ "broadcast", 0, IF_TRACE_NOBC },
{ "-broadcast", IF_TRACE_NOBC, IF_TRACE_NOBC },
{ "raw", IF_TRACE_RAW, IF_TRACE_RAW },
{ "-raw", 0, IF_TRACE_RAW },
{ "ascii", IF_TRACE_ASCII, IF_TRACE_ASCII | IF_TRACE_HEX },
{ "-ascii", 0, IF_TRACE_ASCII | IF_TRACE_HEX },
{ "hex", IF_TRACE_HEX, IF_TRACE_ASCII | IF_TRACE_HEX },
{ "-hex", IF_TRACE_ASCII, IF_TRACE_ASCII | IF_TRACE_HEX },
#ifdef MONITOR
/* borrow a meaningless combination for the new trace type */
#define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
{ "monitor", IF_TRACE_PLAIN, IF_TRACE_ASCII | IF_TRACE_HEX },
{ "-monitor", IF_TRACE_ASCII, IF_TRACE_ASCII | IF_TRACE_HEX },
#endif
{ "off", 0, 0xffff },
{ NULLCHAR, 0, 0 }
};
void
dump (register struct iface *ifp, int direction, unsigned type, struct mbuf *bp)
{
struct mbuf *tbp;
void (*func) __ARGS ((FILE *, struct mbuf **, int));
int16 size;
time_t timer;
char *cp;
#ifdef KISS /* Let's straighten out this multiport tracing - K5JB */
if (type == CL_KISS) { /* I don't think we will see CL_AX25 */
int port; /* don't need this but it improves readability */
struct iface *kifp;
port = (bp->data[0] & 0xF0) >> 4;
if ((kifp = Slip[ifp->xdev].kiss[port]) != NULLIF)
ifp = kifp;
}
#endif
if (ifp == NULL || (ifp->trace & direction) == 0)
return; /* Nothing to trace */
#ifdef UNIX
/* need to check if the traced-to session is a "blocking" session */
if (ifp->trsock != -1 && sm_blocked (Tracesession ? Trace : Command))
return;
#else
if (Tracesession) {
/* Disable trace if this is not Trace-sessions,
* or when shelled out, and not tracing to file */
#ifdef MULTITASK
if ((Current != Trace || Nokeys) && (ifp->trfp == stdout))
#else
if ((Current != Trace) && (ifp->trfp == stdout))
#endif /* MULTITASK */
return; /* Nothing to trace */
} else {
/* Disable trace on non-command sessions or when shelled out */
#ifdef MULTITASK
if ((Current != Command || Nokeys) && (ifp->trfp == stdout))
#else
if ((Current != Command) && (ifp->trfp == stdout))
#endif
return; /* Nothing to trace */
}
#endif
if (ifp->trsock != -1)
tracesock = ifp->trsock;
else if (Tracesession)
tracesock = Trace->output;
else
tracesock = Command->output;
(void) time (&timer);
cp = ctime (&timer);
cp[24] = '\0';
switch (direction) {
case IF_TRACE_IN:
if ((ifp->trace & IF_TRACE_NOBC)
&& (Tracef[type].addrtest != NULLFP ((struct iface *, struct mbuf *)))
&& (*Tracef[type].addrtest) (ifp, bp) == 0)
return; /* broadcasts are suppressed */
#ifdef MONITOR
if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
else
#endif
traceprintf (ifp->trfp, "\n%s - %s recv:\n", cp, ifp->name);
break;
case IF_TRACE_OUT:
#ifdef MONITOR
if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
else
#endif
traceprintf (ifp->trfp, "\n%s - %s sent:\n", cp, ifp->name);
break;
default:
break;
}
if (bp == NULLBUF || (size = len_p (bp)) == 0) {
traceprintf (ifp->trfp, "empty packet!!\n");
return;
}
if (type < NCLASS)
func = Tracef[type].tracef;
else
func = NULLVFP ((FILE *, struct mbuf **, int));
(void) dup_p (&tbp, bp, 0, size);
if (tbp == NULLBUF) {
traceprintf (ifp->trfp, nospace);
return;
}
#ifdef MONITOR
Trace_compact_header = ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN);
#endif
if (func != NULLVFP ((FILE *, struct mbuf **, int)))
(*func) (ifp->trfp, &tbp, 1);
#ifdef MONITOR
if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
plain_dump (ifp->trfp, &tbp);
else
#endif
if (ifp->trace & IF_TRACE_ASCII) {
/* Dump only data portion of packet in ascii */
ascii_dump (ifp->trfp, &tbp);
} else if (ifp->trace & IF_TRACE_HEX) {
/* Dump entire packet in hex/ascii */
free_p (tbp);
(void) dup_p (&tbp, bp, 0, len_p (bp));
if (tbp != NULLBUF)
hex_dump (ifp->trfp, &tbp, ifp->type);
else
traceprintf (ifp->trfp, nospace);
}
free_p (tbp);
}
/* Dump packet bytes, no interpretation */
void
raw_dump (struct iface *ifp, int direction, struct mbuf *bp)
{
struct mbuf *tbp;
/* Dump entire packet in hex/ascii */
traceprintf (ifp->trfp, "\n******* raw packet dump (%s %s)\n",
((direction & IF_TRACE_OUT) ? "send" : "recv"), ifp->name);
(void) dup_p (&tbp, bp, 0, len_p (bp));
if (tbp != NULLBUF)
hex_dump (ifp->trfp, &tbp, ifp->type);
else
traceprintf (ifp->trfp, nospace);
traceprintf (ifp->trfp, "*******\n");
free_p (tbp);
return;
}
/* Dump an mbuf in hex */
static void
hex_dump (FILE * fp, register struct mbuf **bpp, int iftype)
{
int16 n;
int16 address;
char buf[16];
if (bpp == NULLBUFP || *bpp == NULLBUF)
return;
address = 0;
if (iftype == CL_AX25)
(void) pullup (bpp, (unsigned char *) buf, 1); /* remove first zero byte */
while ((n = pullup (bpp, (unsigned char *) buf, sizeof (buf))) != 0) {
fmtline (fp, address, buf, n);
address += n;
}
}
/* Dump an mbuf in ascii */
static void
ascii_dump (FILE * fp, register struct mbuf **bpp)
{
int c;
register int16 tot;
if (bpp == NULLBUFP || *bpp == NULLBUF)
return;
tot = 0;
while ((c = PULLCHAR (bpp)) != -1) {
if ((tot % 64) == 0)
traceprintf (fp, "%04x ", tot);
traceprintf (fp, "%c", isprint (uchar (c)) ? c : '.');
if ((++tot % 64) == 0)
traceprintf (fp, "\n");
}
if ((tot % 64) != 0)
traceprintf (fp, "\n");
}
/* Print a buffer up to 16 bytes long in formatted hex with ascii
* translation, e.g.,
* 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
*/
static void
fmtline (FILE * fp, int16 addr, char *buf, int16 len)
{
char line[100];
register char *aptr, *cptr;
register char c;
memset (line, ' ', sizeof (line));
ctohex (line, (int16) hibyte (addr));
ctohex (line + 2, (int16) lobyte (addr));
aptr = &line[6];
cptr = &line[55];
while (len-- != 0) {
c = *buf++;
ctohex (aptr, (int16) uchar (c));
aptr += 3;
c &= 0x7f;
*cptr++ = isprint (uchar (c)) ? c : '.';
}
*cptr++ = '\n';
*cptr = 0;
traceprintf (fp, "%s", line);
}
/* Convert byte to two ascii-hex characters */
static void
ctohex (register char *buf, register int16 c)
{
static char hex[] = "0123456789abcdef";
*buf++ = hex[hinibble (c)];
*buf = hex[lonibble (c)];
}
#ifdef MONITOR
/* Dump an mbuf in ascii with newlines but no others. */
/* Actually, we do limited VT100 parsing, since that seems popular here */
static void
plain_dump (FILE * fp, register struct mbuf **bpp)
{
struct mbuf *tmp, **tmpp = &tmp;
int c, esc, nl;
if (bpp == NULLBUFP || *bpp == NULLBUF)
return;
/* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
(void) dup_p (&tmp, *bpp, 0, len_p (*bpp));
nl = 0;
while ((c = PULLCHAR (tmpp)) != -1) {
/*
* Printable characters are okay, as are \n \t \r \b \f \a \E
* Nulls and other control characters are verboten, as are meta
* controls. Meta-printables are accepted, since they may be
* intended as PC graphics (but don't expect them to dump right
* from here because I don't decode them. Maybe someday).
*/
if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
(c > 126 && c < 174) || c > 223)
nl = 1;
}
if (nl) {
ascii_dump (fp, bpp);
return;
}
esc = 0;
nl = 1;
while ((c = PULLCHAR (bpp)) != -1) {
if (c == 0x1B)
esc = !esc;
else if (esc == 1 && c == '[')
esc = 2;
else if (esc == 1)
esc = 0;
else if (esc == 2 && c != ';' && !isdigit (c)) {
/* handle some common cases? */
esc = 0;
} else if (esc == 0 && c == '\r') {
traceprintf (fp, "\n");
nl = 1;
}
/* safe programming: not everyone *always* agrees on isprint */
else if (esc == 0 && c != '\n' && (isprint (c) || c == '\t')) {
traceprintf (fp, "%c", c);
nl = 0;
}
}
if (!nl)
traceprintf (fp, "\n");
}
#endif
/* Modify or displace interface trace flags */
int
dotrace (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
struct tracecmd *tp;
if (argc < 2) {
for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
showtrace (ifp);
return 0;
}
if ((ifp = if_lookup (argv[1])) == NULLIF) {
tprintf (Badinterface, argv[1]);
return 1;
}
#if 0
if (ifp->port) {
tprintf ("No trace on this interface - use master.\n");
return 1;
}
#endif
if (argc == 2) {
showtrace (ifp);
return 0;
}
/* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
if (argc >= 3) {
for (tp = Tracecmd; tp->name != NULLCHAR; tp++)
if (strncmp (tp->name, argv[2], strlen (argv[2])) == 0)
break;
if (tp->name != NULLCHAR)
ifp->trace = (int16) ((ifp->trace & (~(unsigned)tp->mask)) | (unsigned)tp->val);
else
ifp->trace = (int16) htoi (argv[2]);
}
/* Always default to stdout unless trace file is given */
if (ifp->trsock != -1)
close_s (ifp->trsock);
ifp->trsock = -1;
if (ifp->trfp != NULLFILE && ifp->trfp != stdout) /*lint !e740 */
fclose (ifp->trfp);
ifp->trfp = stdout; /*lint !e740 */
if (ifp->trfile != NULLCHAR)
free (ifp->trfile);
ifp->trfile = NULLCHAR;
if (argc >= 4) {
if (argv[3][0] == '!') {
/* trace to the current output socket ! */
ifp->trsock = Curproc->output;
/* make sure stopping trace doesn't kill connection */
(void) usesock (ifp->trsock);
} else if ((ifp->trfp = fopen (argv[3], APPEND_TEXT)) == NULLFILE) {
tprintf ("Can't write to %s\n", argv[3]);
ifp->trfp = stdout; /*lint !e740 */
} else {
ifp->trfile = strdup (argv[3]);
}
}
showtrace (ifp);
return 0;
}
/* Display the trace flags for a particular interface */
static void
showtrace (register struct iface *ifp)
{
if (ifp == NULLIF)
return;
tprintf ("%s:", ifp->name);
#if 0
if (ifp->port) {
tprintf (" trace on master interface only.\n");
return;
}
#endif
if (ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)) {
if (ifp->trace & IF_TRACE_IN)
tprintf (" input");
if (ifp->trace & IF_TRACE_OUT)
tprintf (" output");
if (ifp->trace & IF_TRACE_NOBC)
tprintf (" - no broadcasts");
#ifdef MONITOR
if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
tprintf (" (Monitoring)");
else
#endif
if (ifp->trace & IF_TRACE_HEX)
tprintf (" (Hex/ASCII dump)");
else if (ifp->trace & IF_TRACE_ASCII)
tprintf (" (ASCII dump)");
else
tprintf (" (headers only)");
if (ifp->trace & IF_TRACE_RAW)
tprintf (" Raw output");
if (ifp->trfile != NULLCHAR)
tprintf (" trace file: %s", ifp->trfile);
else if (ifp->trsock >= SOCKBASE)
tprintf (" tracing to socket");
tprintf ("\n");
} else
tprintf (" tracing off\n");
}
/* shut down all trace files */
void
shuttrace ()
{
struct iface *ifp;
for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
if (ifp->trsock != -1)
close_s (ifp->trsock);
if (ifp->trfp != NULLFILE && ifp->trfp != stdout) /*lint !e740 */
fclose (ifp->trfp);
if (ifp->trfile != NULLCHAR)
free (ifp->trfile);
ifp->trfile = NULLCHAR;
ifp->trfp = NULLFILE;
ifp->trsock = -1;
}
}
#endif /*TRACE*/
#ifdef PPP
/* Log messages of the form
* Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
*/
#if defined(ANSIPROTO)
#if defined(SCREENSAVER) && defined(UNIX)
extern int16 intrace;
#endif
void
trace_log (struct iface *ifp, const char *fmt,...)
{
va_list ap;
char *cp;
long t;
if (ifp->trfp == NULLFILE)
return;
(void) time (&t);
cp = ctime (&t);
rip (cp);
traceprintf (ifp->trfp, "%s", cp);
traceprintf (ifp->trfp, " - ");
va_start (ap, fmt); /*lint !e718 !e746 */
#if defined(SCREENSAVER) && defined(UNIX)
intrace = 1;
#endif
if (ifp->trfp == stdout) /*lint !e740 */
(void) usvprintf (tracesock, fmt, ap);
else
(void) vfprintf (ifp->trfp, fmt, ap);
#if defined(SCREENSAVER) && defined(UNIX)
intrace = 0;
#endif
va_end (ap);
traceprintf (ifp->trfp, "\n");
}
#else
/* VARARGS2 */
void
trace_log (ifp, fmt, arg1, arg2, arg3, arg4, arg5)
struct iface *ifp;
const char *fmt;
int arg1, arg2, arg3, arg4, arg5;
{
char *cp;
long t;
if (ifp->trfp == NULLFILE)
return;
time (&t);
cp = ctime (&t);
rip (cp);
traceprintf (ifp->trfp, "%s", cp);
traceprintf (ifp->trfp, " - ");
traceprintf (ifp->trfp, fmt, arg1, arg2, arg3, arg4, arg5);
traceprintf (ifp->trfp, "\n");
}
#endif
#endif /* PPP */